"""
AIPPT API Client
Handles all HTTP requests to AIPPT API
"""
import requests
import json
from typing import Dict, Any, Optional, List, BinaryIO
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

from src.llm.aippt_app.config.aippt_config import AIPPTConfig


class AIPPTAPIClient:
    """AIPPT API Client for making HTTP requests"""

    def __init__(self, config: Optional[AIPPTConfig] = None):
        """
        Initialize AIPPT API client

        Args:
            config: AIPPTConfig instance, uses default if not provided
        """
        self.config = config or AIPPTConfig()
        self.config.validate_config()
        self.session = self._create_session()

    def _create_session(self) -> requests.Session:
        """Create requests session with retry strategy"""
        session = requests.Session()

        # Configure retry strategy
        retry_strategy = Retry(
            total=self.config.MAX_RETRIES,
            backoff_factor=1,
            status_forcelist=[429, 500, 502, 503, 504],
            allowed_methods=["HEAD", "GET", "OPTIONS", "POST"]
        )
        adapter = HTTPAdapter(max_retries=retry_strategy)
        session.mount("https://", adapter)
        session.mount("http://", adapter)

        return session

    def _make_request(
        self,
        method: str,
        endpoint: str,
        **kwargs
    ) -> Dict[str, Any]:
        """
        Make HTTP request to AIPPT API

        Args:
            method: HTTP method (GET, POST, etc.)
            endpoint: API endpoint (e.g., '/ppt/templates')
            **kwargs: Additional arguments for requests

        Returns:
            Response data as dictionary

        Raises:
            requests.RequestException: If request fails
        """
        url = f"{self.config.BASE_URL}{endpoint}"

        # Add default timeout if not specified
        if 'timeout' not in kwargs:
            kwargs['timeout'] = self.config.REQUEST_TIMEOUT

        # Add default headers if not specified
        if 'headers' not in kwargs:
            # Check if multipart/form-data (files parameter present)
            if 'files' in kwargs:
                kwargs['headers'] = self.config.get_multipart_headers()
            else:
                kwargs['headers'] = self.config.get_headers()

        try:
            response = self.session.request(method, url, **kwargs)
            response.raise_for_status()

            # Try to parse JSON response
            try:
                return response.json()
            except json.JSONDecodeError:
                # If not JSON, return text
                return {'data': response.text}

        except requests.RequestException as e:
            # Log error and re-raise
            print(f"Request failed: {method} {url}, Error: {str(e)}")
            raise

    # ============================================================
    # Template APIs
    # ============================================================

    def get_template_options(self) -> Dict[str, Any]:
        """
        Get template filter options

        Returns:
            Template filter options
        """
        return self._make_request('GET', '/ppt/template/options')

    def list_templates(
        self,
        current: int = 1,
        size: int = 10,
        lang: str = 'zh',
        template_type: int = 1,
        category: Optional[str] = None,
        style: Optional[str] = None,
        theme_color: Optional[str] = None
    ) -> Dict[str, Any]:
        """
        List templates with pagination

        Args:
            current: Current page number
            size: Page size
            lang: Language code (zh, en, etc.)
            template_type: Template type (1=system templates, 4=user custom templates)
            category: Filter by category
            style: Filter by style
            theme_color: Filter by theme color

        Returns:
            Template list response
        """
        # Add lang as query parameter in URL
        endpoint = f'/ppt/templates?lang={lang}'

        # Build filters object (type is required!)
        filters = {
            'type': template_type
        }

        if category:
            filters['category'] = category
        if style:
            filters['style'] = style
        if theme_color:
            filters['themeColor'] = theme_color

        # Correct payload format according to API docs
        payload = {
            'page': current,
            'size': size,
            'filters': filters
        }

        return self._make_request('POST', endpoint, json=payload)

    def get_random_templates(self, count: int = 5) -> Dict[str, Any]:
        """
        Get random templates

        Args:
            count: Number of templates to fetch

        Returns:
            Random template list
        """
        payload = {'count': count}
        return self._make_request('POST', '/ppt/randomTemplates', json=payload)

    # ============================================================
    # Task APIs (V2)
    # ============================================================

    def create_task(
        self,
        task_type: int,
        content: Optional[str] = None,
        files: Optional[List[tuple]] = None
    ) -> Dict[str, Any]:
        """
        Create a PPT generation task

        Args:
            task_type: Task type (1-7)
            content: Task content (varies by type)
            files: List of file tuples in format ('file', (filename, content, content_type))

        Returns:
            Task creation response with task ID
        """
        # Prepare multipart form data
        form_data = {
            'type': (None, str(task_type))
        }

        if content:
            form_data['content'] = (None, content)

        # Add files if provided
        if files:
            # Files are already in the correct format from the router
            return self._make_request('POST', '/ppt/v2/createTask', files={**form_data, **dict(files)})
        else:
            return self._make_request('POST', '/ppt/v2/createTask', files=form_data)

    def get_generation_options(self, lang: str = 'zh') -> Dict[str, Any]:
        """
        Get generation options for V2 API

        Args:
            lang: Language code (default: zh)

        Returns:
            Generation options
        """
        return self._make_request('GET', f'/ppt/v2/options?lang={lang}')

    def generate_content(
        self,
        task_id: str,
        is_stream: bool = False,
        prompt: Optional[str] = None,
        template_id: Optional[str] = None,
        **options
    ) -> Dict[str, Any]:
        """
        Generate outline and content for a task

        Args:
            task_id: Task ID from create_task
            is_stream: Whether to use streaming response
            prompt: Additional prompt for generation
            template_id: Template ID to use
            **options: Additional generation options (audience, lang, pageCount, etc.)

        Returns:
            Generated content response
        """
        payload = {
            'taskId': task_id,
            'isStream': is_stream,
            **options
        }

        if prompt:
            payload['prompt'] = prompt
        if template_id:
            payload['templateId'] = template_id

        return self._make_request('POST', '/ppt/v2/generateContent', json=payload)

    def update_content(
        self,
        task_id: str,
        question: str,
        is_stream: bool = False
    ) -> Dict[str, Any]:
        """
        Update/modify content based on user instruction

        Args:
            task_id: Task ID
            question: User instruction to modify content
            is_stream: Whether to use streaming response

        Returns:
            Updated content response
        """
        payload = {
            'taskId': task_id,
            'question': question,
            'isStream': is_stream
        }
        return self._make_request('POST', '/ppt/v2/updateContent', json=payload)

    def generate_pptx(
        self,
        task_id: str,
        markdown: str,
        template_id: str
    ) -> Dict[str, Any]:
        """
        Generate PPT file from markdown content

        Args:
            task_id: Task ID
            markdown: Markdown outline and content
            template_id: Template ID to use

        Returns:
            PPT generation response with file URL
        """
        payload = {
            'id': task_id,  # Fixed: Use 'id' instead of 'taskId' according to API doc
            'markdown': markdown,
            'templateId': template_id
        }

        return self._make_request('POST', '/ppt/v2/generatePptx', json=payload)

    # ============================================================
    # PPT Management APIs
    # ============================================================

    def list_pptx(self, current: int = 1, size: int = 10) -> Dict[str, Any]:
        """
        List user's PPT works

        Args:
            current: Current page number
            size: Page size

        Returns:
            PPT list response
        """
        payload = {
            'current': current,
            'size': size
        }
        return self._make_request('POST', '/ppt/listPptx', json=payload)

    def load_pptx(self, ppt_id: str) -> Dict[str, Any]:
        """
        Load complete PPT data

        Args:
            ppt_id: PPT ID

        Returns:
            Complete PPT data
        """
        return self._make_request('GET', f'/ppt/loadPptx?id={ppt_id}')

    def download_pptx(self, ppt_id: str) -> Dict[str, Any]:
        """
        Download PPT file

        Args:
            ppt_id: PPT ID

        Returns:
            Download URL response
        """
        payload = {'id': ppt_id}
        return self._make_request('POST', '/ppt/downloadPptx', json=payload)

    def delete_pptx(self, ppt_id: str) -> Dict[str, Any]:
        """
        Delete PPT

        Args:
            ppt_id: PPT ID

        Returns:
            Deletion response
        """
        payload = {'id': ppt_id}
        return self._make_request('POST', '/ppt/delete', json=payload)
